package org.devocean.groupbuying.web.frontend;

import java.io.UnsupportedEncodingException;
import java.security.NoSuchAlgorithmException;
import java.security.Principal;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import org.devocean.groupbuying.domain.Article;
import org.devocean.groupbuying.domain.Comment;
import org.devocean.groupbuying.domain.Customer;
import org.devocean.groupbuying.domain.Purchase;
import org.devocean.groupbuying.domain.PurchaseItem;
import org.devocean.groupbuying.domain.Role;
import org.devocean.groupbuying.domain.SerialKey;
import org.devocean.groupbuying.service.CommentService;
import org.devocean.groupbuying.service.CustomerService;
import org.devocean.groupbuying.service.RoleService;
import org.devocean.groupbuying.service.SerialKeyService;
import org.devocean.groupbuying.service.mail.MailService;
import org.devocean.groupbuying.utils.Hashing;
import org.devocean.groupbuying.utils.TokenGenerator;
import org.devocean.groupbuying.web.frontend.displaybeans.SerialKeyBean;
import org.devocean.groupbuying.web.validator.AccountValidator;
import org.devocean.groupbuying.web.validator.EmailValidator;
import org.devocean.groupbuying.web.validator.PasswordValidator;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

@Controller
@RequestMapping(value = "/customers")
public class CustomerController {

	@Autowired
	private CustomerService customerService;

	@Autowired
	private AccountValidator accountValidator;
	
	@Autowired
	private EmailValidator emailValidator;

	@Autowired
	private CommentService commentService;

	@Autowired
	private RoleService roleService;

	@Autowired
	private MailService mailService;

	@Autowired
	private SerialKeyService serialKeyService;
	
	@Value("#{Path['path']}")
	private String path;

	@RequestMapping(value = "/login")
	public String login() {
		return "login";
	}

	@RequestMapping(value = "/loginfailed", method = RequestMethod.GET)
	public String loginerror(ModelMap model) {

		model.addAttribute("error", "true");
		return "login";

	}

	@RequestMapping(value = "/logout")
	public String logout() {

		return "/";

	}

	// @inReview
	@RequestMapping(value = "/purchases")
	public String getPurchases(ModelMap map, Principal principal) {
		Customer Customer = customerService.getCustomerById(Integer
				.parseInt(principal.getName()));
		Set<Purchase> purchases = Customer.getPurchases();
		Set<PurchaseItem> purchaseItems = new HashSet<PurchaseItem>();

		for (Purchase purchase : purchases) {
			for (PurchaseItem purchaseItem : purchase.getItems()) {
				purchaseItems.add(purchaseItem);
			}
		}
		map.addAttribute("purchaseItems", purchaseItems);

		return "purchases";
	}

	@RequestMapping(value = "/account")
	public String getAccount(ModelMap map, Principal principal) {
		
		Customer customer = customerService.getCustomerById(Integer
				.parseInt(principal.getName()));
		map.addAttribute("customer", customer);
		
		map.put("credit", customer.getCredit());
		return "account";
	}

	@RequestMapping(value = "/editAccount")
	public String editAccount(ModelMap map, Principal principal) {

		map.addAttribute("newCustomer", customerService.getCustomerById(Integer
				.parseInt(principal.getName())));
		return "editAccount/edit";
	}

	@RequestMapping(value = "/editAccount", method = RequestMethod.PUT)
	public String updateAccount(String actualPassword,
			@ModelAttribute("newCustomer") Customer newCustomer, ModelMap map,
			BindingResult result, Principal principal) {
		
		
		final Customer customer = customerService.getCustomerById(Integer
				.parseInt(principal.getName()));
		String hashPassword=null;
		try {
			hashPassword = Hashing.getHashCode(actualPassword);
		} catch (Exception e) {
			e.printStackTrace();
		}
		if(!customer.getPassword().equals(hashPassword)){
			System.out.println("if");
			result.rejectValue("actualPassword", "actual password not match", "actual password not match");
		}
		System.out.println(result);

		if (!result.hasErrors()) {

			
//			customer.setEmail(newCustomer.getEmail());
//			customer.setUserName(newCustomer.getUserName());
//			customer.setPhone(newCustomer.getPhone());
//			customer.setAdress(newCustomer.getAdress());
//			customer.setState(newCustomer.getState());
//			customer.setZipCode(newCustomer.getZipCode());
//			customer.setCity(newCustomer.getCity());
//			customerService.addOrUpdateCustomer(customer);
//			mailService.notifyUpdatedCustomer(customer);
//			map.clear();
			return "redirect:/customers/vouchers";
		}
		return "editAccount/edit";

	}

	@RequestMapping(value = "/addAccount")
	public String addAccount(ModelMap map) {
		map.addAttribute("newCustomer", new Customer());
		return "addAccount/add";
	}

	@RequestMapping(value = "/addAccount", method = RequestMethod.POST)
	public String addnewAccount(
			@ModelAttribute("newCustomer") Customer newCustomer,
			BindingResult result) {
		
		new PasswordValidator().validate(newCustomer, result);
		accountValidator.validate(newCustomer, result);
		System.out.println(result.getAllErrors());
		if (!result.hasErrors()) {

			Set<Role> roles = new HashSet<Role>();
			roles.add(roleService.getAuthority("Role_CLIENT"));
			newCustomer.setCustomerRoles(roles);
			newCustomer.setUserName(newCustomer.getEmail());
			newCustomer.setEnabled(true);
			newCustomer.setCredit(0.0);
			customerService.addOrUpdateCustomer(newCustomer);
			mailService.notifyNewCustomer(newCustomer);
			return "redirect:/customers/";

		}
		return "addAccount/add";

	}

	@RequestMapping(value = "/editPassword")
	public String editPassword(ModelMap map) {

		return "editPassword";
	}

	@RequestMapping(value = "/editPassword", method = RequestMethod.PUT)
	public String updatePassword(String password,HttpServletRequest request) {

			HttpSession session = request.getSession();
			String sessionEmail = session.getAttribute("email").toString();
			Customer customer = customerService.getCustomerByEmail(sessionEmail);
			customer.setPassword(password);
			customerService.updatePasswordCustomer(customer);
			session.setAttribute("token", null);
			session.setAttribute("email", null);
			return "confirmationPasswordUpdate";		

	}

	// @RequestMapping(value = "/", produces = "text/html")
	// public String index(ModelMap map,Principal
	// principal,@CookieValue(value="clientLanguage") String lang) {
	// System.out.println("lang : "+lang);
	// List<SerialKeyBean> serialKeyBeans = new ArrayList<SerialKeyBean>();
	// Customer customer = customerService.getCustomerById(Integer
	// .parseInt(principal.getName()));
	// List<Purchase> purchases =
	// purchaseService.getPurchaseByCustomerAndLang(customer,lang);
	// for (Purchase purchase : purchases) {
	// for (PurchaseItem item : purchase.getItems()) {
	// for (SerialKey key : item.getSerialKeys()) {
	// serialKeyBeans.add(new SerialKeyBean(key, item));
	// }
	// }
	// }
	// System.out.println(serialKeyBeans.toString());
	// map.addAttribute("serialKeyBeans", serialKeyBeans);
	// return "purchases";
	//
	// }
	@RequestMapping("vouchers")
	public String firstPaginate(Map<String, Object> map, Principal principal) {

		return "redirect:/customers/vouchers/1/3/";
	}

	@RequestMapping("vouchers/{index}/{max}")
	public String paginate(Map<String, Object> map,
			@PathVariable("index") Integer index,
			@PathVariable("max") Integer max, Principal principal) {
		Customer customer = customerService.getCustomerById(Integer
				.parseInt(principal.getName()));
		//
		long count = serialKeyService.countSerialKeyByCustomer(customer
				.getCustomerID());
		map.put("count", count);
		long pages = Math.round((new Float(count) / new Float(max)));
		if (pages < (new Float(count) / new Float(max))) {
			pages = pages + 1;
		}
		int start = (int) ((index * max) - max);

		map.put("pages", pages);
		map.put("index", index);
		List<SerialKey> serialKeys = new ArrayList<SerialKey>();
		List<SerialKeyBean> serialKeysBeans = new ArrayList<SerialKeyBean>();
		serialKeys = serialKeyService.getSerialKeyByCustomer(customer, start,
				max);
		for (SerialKey serialKey : serialKeys) {
			serialKeysBeans.add(new SerialKeyBean(serialKey));
		}
		map.put("credit", customer.getCredit());
		System.out.println(serialKeys.toString());
		map.put("serialKeyBeans", serialKeysBeans);
		map.put("path", "customers/vouchers/");
		
		return "vouchers";
	}

	@RequestMapping("vouchers/expireDate/{index}/{max}")
	public String paginateByExpireDate(Map<String, Object> map,
			@PathVariable("index") Integer index,
			@PathVariable("max") Integer max, Principal principal) {
		Customer customer = customerService.getCustomerById(Integer
				.parseInt(principal.getName()));
		//
		long count = serialKeyService
				.countSerialKeyByCustomerByExpireDate(customer.getCustomerID());
		map.put("count", count);
		long pages = Math.round((new Float(count) / new Float(max)));
		if (pages < (new Float(count) / new Float(max))) {
			pages = pages + 1;
		}
		int start = (int) ((index * max) - max);

		map.put("pages", pages);
		map.put("index", index);
		List<SerialKey> serialKeys = new ArrayList<SerialKey>();
		List<SerialKeyBean> serialKeysBeans = new ArrayList<SerialKeyBean>();
		serialKeys = serialKeyService.getSerialKeyByCustomerByExpireDate(
				customer.getCustomerID(), start, max);
		for (SerialKey serialKey : serialKeys) {
			serialKeysBeans.add(new SerialKeyBean(serialKey));
		}
		System.out.println(serialKeys.toString());
		map.put("serialKeyBeans", serialKeysBeans);
		map.put("path", "customers/vouchers/expireDate/");
		return "vouchers";
	}

	@RequestMapping("vouchers/purchaseDate/{index}/{max}")
	public String paginateByPurchaseDate(Map<String, Object> map,
			@PathVariable("index") Integer index,
			@PathVariable("max") Integer max, Principal principal) {
		Customer customer = customerService.getCustomerById(Integer
				.parseInt(principal.getName()));
		//
		long count = serialKeyService
				.countSerialKeyByCustomerByPurchaseDate(customer
						.getCustomerID());
		map.put("count", count);
		long pages = Math.round((new Float(count) / new Float(max)));
		if (pages < (new Float(count) / new Float(max))) {
			pages = pages + 1;
		}
		int start = (int) ((index * max) - max);

		map.put("pages", pages);
		map.put("index", index);
		List<SerialKey> serialKeys = new ArrayList<SerialKey>();
		List<SerialKeyBean> serialKeysBeans = new ArrayList<SerialKeyBean>();
		serialKeys = serialKeyService.getSerialKeyByCustomerByPurchaseDate(
				customer.getCustomerID(), start, max);
		for (SerialKey serialKey : serialKeys) {
			serialKeysBeans.add(new SerialKeyBean(serialKey));
		}
		System.out.println(serialKeys.toString());
		map.put("serialKeyBeans", serialKeysBeans);
		map.put("path", "customers/vouchers/purchaseDate/");
		return "vouchers";
	}

	@RequestMapping("vouchers/markUnused/{serialKeyID}")
	public String markUnused(Map<String, Object> map,
			@PathVariable("serialKeyID") Integer serialKeyID) {

		SerialKey serialKey = serialKeyService.getSerialKeyById(serialKeyID);
		serialKey.setUsed(false);
		serialKeyService.updateSerialKey(serialKey);
		return "redirect:/customers/vouchers/";
	}

	@RequestMapping("vouchers/markUsed/{serialKeyID}")
	public String markUsed(Map<String, Object> map,
			@PathVariable("serialKeyID") Integer serialKeyID) {

		SerialKey serialKey = serialKeyService.getSerialKeyById(serialKeyID);
		serialKey.setUsed(true);
		serialKeyService.updateSerialKey(serialKey);
		return "redirect:/customers/vouchers/";
	}

	@RequestMapping("vouchers/activationCode/{serialKeyID}")
	public String activationCode(
			@PathVariable("serialKeyID") Integer serialKeyID) {
		SerialKey serialKey = serialKeyService.getSerialKeyById(serialKeyID);
		String location = serialKey.getVoucher().getVoucherLocation();

		return "redirect:/" + location;
	}

	@RequestMapping(value = "/postComment")
	public String postComment(ModelMap map, Article article, Customer customer,
			String text, Principal principal) {
		Comment comment = new Comment();
		System.out.println(article);
		comment.setArticle(article);
		comment.setCustomer(customerService.getCustomerById(Integer
				.parseInt(principal.getName())));
		comment.setText(text);
		comment.setCommentDate(Calendar.getInstance().getTime());
		map.addAttribute("comment", commentService.addOrUpdateComment(comment));
		return "comment";
	}

	@RequestMapping(value = "/reply")
	public String reply(ModelMap map, Comment comment, Customer customer,
			String text) {
		Comment reply = new Comment();
		reply.setArticle(comment.getArticle());
		reply.setComment(comment);
		reply.setCustomer(customer);
		reply.setText(text);
		reply.setCommentDate(Calendar.getInstance().getTime());
		comment.add(reply);
		map.addAttribute("comment", commentService.addOrUpdateComment(comment));
		return "comment";
	}
	
	@RequestMapping(value="/forgotPassword")
	public String forgotPassword(ModelMap map){
		map.addAttribute("customer", new Customer());
		return "forgotPassword";
	}
	
	@RequestMapping(value="/forgotPassword",method = RequestMethod.POST)
	public String sendPasswordToCustomer(String email,HttpServletRequest request,
			@ModelAttribute("customer") Customer newCustomer,
			BindingResult result){
		
		System.out.println("email : "+newCustomer.getEmail());
//		
		
		emailValidator.validate(newCustomer, result);
		if(!result.hasErrors()){
		String token = TokenGenerator.nextString();
		System.out.println("email :" +email);
		String localPath = request.getContextPath() + "/";
		String uri =path + localPath + "customers/forgotPassword/"
				+token ;
		Customer customer = customerService.getCustomerByEmail(newCustomer.getEmail());
		mailService.forgotPassword(customer, uri);
		HttpSession session = request.getSession();
		session.setAttribute("token", token);
		session.setAttribute("email", email);
		
		return "confirmationSendEmail";
		}
		else 
			return "forgotPassword";
	}
	
	@RequestMapping(value="/forgotPassword/{token}")
	public String verifyCustomer(HttpServletRequest request,ModelMap map,@PathVariable("token") String token){
		HttpSession session = request.getSession();
		Boolean flag = false;
		if (session.getAttribute("token")!=null) {
			String sessionToken = session.getAttribute("token").toString();
			System.out.println(sessionToken);
			if(sessionToken.equals(token)){
				flag = false;
			}
			else{
				flag = true;
			}
		}
		else{
			flag = true;
		}
		if(flag){
		map.put("msg", "this token has expired");
		return "error";
		}
		else{
			return "redirect:/customers/editPassword";
			
		}
	}

}
